/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package learn;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 *
 * @author phong
 */
public class Lexicon {
    
    Map<LexicalSurface, Map<LexicalEntry,Integer>> c;       // c(surf, le) : count
    Map<LexicalSurface, Integer> N;                         // c(surf) = sum_{le} c(surf, le)
    Map<LexicalSurface, Map<Integer,Integer>> Nc;           // Nc(surf, c) = | {le | c(surf,le) = c}  |
    
    public Lexicon() {
        c = new HashMap<LexicalSurface, Map<LexicalEntry, Integer>>();
        N = new HashMap<LexicalSurface, Integer>();
        Nc = new HashMap<LexicalSurface, Map<Integer, Integer>>();
    }

    public void add(LexicalEntry le) {
        LexicalSurface surf = le.getLexSurf();
        
        Map<LexicalEntry, Integer> local = this.c.get(surf);
        if (local == null) {
            local = new LinkedHashMap<LexicalEntry, Integer>();
            Map<Integer,Integer> local1 = new HashMap<Integer,Integer>();
            local.put(le, 1);
            local1.put(1, 1);
            N.put(surf, 1);
            c.put(surf, local);
            Nc.put(surf, local1);
        }
        else {
            Integer count = local.get(le);
            if (count == null)
                count = 0;
            local.put(le, count + 1);
            N.put(surf, N.get(surf) + 1);
            
            Map<Integer,Integer> local1 = Nc.get(surf);
            if (count > 0)
                local1.put(count, local1.get(count)-1);
            Integer Ncpp = local1.get(count+1);
            if (Ncpp == null)
                Ncpp = 0;
            local1.put(count+1, Ncpp+1);
        }
    }
    
    public List<LexicalEntry> getLexEntries(LexicalSurface surf) {
        Map<LexicalEntry, Integer> local = this.c.get(surf);
        if (local == null) 
            return new LinkedList<LexicalEntry>();
        else 
            return new LinkedList<LexicalEntry>(local.keySet());
    }
    
    // Good-Turing discount
    public double getScore(LexicalEntry le) {
        LexicalSurface surf = le.getLexSurf();
        Map<LexicalEntry, Integer> local = this.c.get(surf);
        if (local == null) 
            return 1.;
        else {
            Integer count = local.get(le);
            Integer sum = N.get(surf);
            
            Integer N1 = Nc.get(surf).get(1);
            if (N1 == null)
                N1 = 1;
            double scoreForUnseen = N1*1. / sum;
                    
            if (count == null) // unseen 
                return scoreForUnseen;
            else 
                return count*1. / sum * (1-scoreForUnseen);
        }
    }
}
